package com.jzd.fwserver

import com.jzd.fwserver.util.I2Helper
import com.jzd.fwserver.util.toByteArrayByASCII
import io.netty.bootstrap.Bootstrap
import io.netty.channel.ChannelInitializer
import io.netty.channel.ChannelOption
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioDatagramChannel
import java.lang.Thread.sleep
import java.nio.charset.Charset
import java.util.*
import kotlin.collections.ArrayList

/**
 * 使用说明：
 * 实时视频 L X Y //X=通道ID Y=1/0 打开/关闭
 * OSD控制 O X //X=通道ID
 * 参数控制 P X //X=通道ID
 * 手动拍图 T X P //X=通道ID P预置位 默认为
 * 心跳回复 H
 * 8 -- 18点 半小时一张图 ! 1 1 8 0 0 30 18 0
 * 风阈值 W X //X ==1 设置 x ==2读取
 * 安徽OSD控制 A0 X Y/
 *
 * 扩展拍照 P X//X=T通道ID
 * 扩展预置位 S X//X=1 读取 x=2设置 x=3删除
 * 扩展升级 U X//X=1 升级 X=2补丁
 */

class Server
{
    companion object
    {
        @JvmStatic
        fun main(args: Array<String>)
        {
            val group = NioEventLoopGroup()
            val bootstrap = Bootstrap()
            try
            {
                bootstrap.group(group)
                        .channel(NioDatagramChannel::class.java)
                        .option(ChannelOption.SO_BROADCAST, true)
                        .handler(object : ChannelInitializer<NioDatagramChannel>()
                        {
                            override fun initChannel(channel: NioDatagramChannel?)
                            {
                                channel?.pipeline()?.addLast(Encoder())
                                channel?.pipeline()?.addLast(Decoder())
                            }
                        })
                val channel = bootstrap.bind(11038).channel()

                val scan = Scanner(System.`in`)
                while (scan.hasNext())
                {
                    val nextLine = scan.nextLine()
                    if (nextLine.trim() != "")
                    {
                        val split = nextLine.split(" ")
                        //a5 5a
                        // 26 00
                        // 39 39 30 30 30 38 34 33 31 35 36 35 32 35 30 30 30
                        val start = byteArrayOf(
                                0xa5.toByte(),
                                0x5a.toByte(),
                                0x26.toByte(),
                                0x00.toByte(),
                                0x39.toByte(),
                                0x39.toByte(),
                                0x30.toByte(),
                                0x30.toByte(),
                                0x30.toByte(),
                                0x38.toByte(),
                                0x34.toByte(),
                                0x33.toByte(),
                                0x31.toByte(),
                                0x35.toByte(),
                                0x36.toByte(),
                                0x35.toByte(),
                                0x32.toByte(),
                                0x35.toByte(),
                                0x30.toByte(),
                                0x30.toByte(),
                                0x30.toByte()
                        )
                        val result = arrayListOf<Byte>()
                        start.forEach {
                            result.add(it)
                        }
                        // 拍照时间表  适用于白天连续时间
                        if (split[0] == "!")
                        {
                            // !，通道号，预置位，开始小时，开始分钟，间隔小时，间隔分钟，结束小时，结束分钟
                            val channel = split[1].toInt(16)
                            val preset = split[2].toInt(16)
                            val startH = split[3].toInt(16)
                            val startM = split[4].toInt(16)
                            val intervalH = split[5].toInt(16)
                            val intervalM = split[6].toInt(16)
                            val endH = split[7].toInt(16)
                            val endM = split[8].toInt(16)
                            result.add(0x07.toByte())
                            result.add(0xb2.toByte())
                            result.add(0x00.toByte())
                            result.add(0x01.toByte()) // 设置
                            result.add(channel.toByte())
                            result.add(0x00.toByte()) // 组数，临时
                            val timeList = arrayListOf<Int>()
                            val start = startH * 60 + startM
                            val end = endH *60 + endM
                            var now = start
                            while (now < end)
                            {
                                timeList.add(now)
                                now += intervalH * 60 + intervalM
                            }
                            timeList.add(end)
                            for (i in timeList)
                            {
                                result.add((i / 60).toByte())
                                result.add((i % 60).toByte())
                                result.add(preset.toByte())
                            }
                            // 修改临时组数
                            result[26] = timeList.size.toByte()
                        }
                        // 拍照时间表 适用于分段的时间表(按照时间顺序排列) 如00:00-05:00 19:00-23:30
                        else if(split[0] == "@")
                        {
                            // @，通道号，预置位，时间段1开始小时，时间段1开始分钟，时间段1间隔小时，时间段1间隔分钟，时间段1结束小时，时间段1结束分钟
                            //         ......，时间段N小时，时间段N分钟
                            val channel = split[1].toInt(16)
                            val preset = split[2].toInt(16)
                            val section = (split.size - 3) / 6 // 有多少分组
                            result.add(0x07.toByte())
                            result.add(0xb2.toByte())
                            result.add(0x00.toByte())
                            result.add(0x01.toByte()) // 设置
                            result.add(channel.toByte())
                            result.add(0x00.toByte()) // 组数，临时
                            val timeList = arrayListOf<Int>()
                            for (i in 0 until section)
                            {
                                val startH = split[3+6*i].toInt(16)
                                val startM = split[4+6*i].toInt(16)
                                val intervalH = split[5+6*i].toInt(16)
                                val intervalM = split[6+6*i].toInt(16)
                                val endH = split[7+6*i].toInt(16)
                                val endM = split[8+6*i].toInt(16)
                                val start = startH * 60 + startM
                                val end = endH * 60 + endM
                                var now = start
                                while (now < end)
                                {
                                    timeList.add(now)
                                    now += intervalH * 60 + intervalM
                                }
                                timeList.add(end)
                            }
                            for (i in timeList)
                            {
                                result.add((i / 60).toByte())
                                result.add((i % 60).toByte())
                                result.add(preset.toByte())
                            }
                            // 修改临时组数
                            result[26] = timeList.size.toByte()
                        }else if (split[0] == "L" && split[1] == "1") {
                            /**
                             * 0 == L
                             * 1 ==通道ID A为全部
                             * 2 ==操作 1打开 0关闭
                             */

                            println("通道1的实时视频>>>")
                            controlLiveVideo(result,  split[2].toInt(), 1)
                        }else if (split[0] == "L" && split[1] == "2") {
                            println("通道2的实时视频>>>")
                            controlLiveVideo(result,  split[2].toInt(), 2)
                        }else if (split[0] == "L" && split[1] == "4") {
                            println("通道4的实时视频>>>")
                            controlLiveVideo(result,  split[2].toInt(), 4)
                        }else if (split[0] == "L" && split[1] == "A") {
                            println("依次通道1、2、4的实时视频>>>")
                        }else if (split[0] == "O") {
                            println("控制OSD>>>")
                            controlOSD(result, split[1].toInt())
                        }else if (split[0] == "P"){
                            println("控制参数>>>")
                            controlPicCfg(result, split[1].toInt())
                        }else if (split[0] == "T"){
                            println("手动抓拍>>>")
                            controlTakePic(result, split[1].toInt(), split[2].toInt())
                        }else if (split[0] == "H"){
                            println("心跳回复>>>")
                            heartControl(result)
                        }else if (split[0] == "W"){
                            print("风阈值>>")
                            windControl(result, split[1].toInt())
                        }else if (split[0] == "A"){
                            print("安徽OSD设置>>")
                            anOSDControl(result, split[1].toInt(), split[2].toInt())
                        }else if (split[0] == "J"){
                            print("江苏扩展时间表设置>>")
                            /**
                             * type = 0
                             * type = 1
                             * type = 2
                             */
                            timeConfig2Conbtrol(result, split[1].toInt(), split[2].toInt())
                        }else if (split[0] == "S"){
                            print("江苏扩展预置位设置>>")
                            presetConfig2Control(result, split[1].toInt())
                        }else if (split[0] == "U"){
                            print("江苏扩展升级功能>>")
                            updateControl(result, split[1].toInt())
                        }else if(split[0] == "I") {
                            print("江苏AI配置功能>>")
                            aiConfig2Control(result, split[1].toInt())
                        }else if (split[0] == "B" && split[1] == "O"){
                            print("湖北OSD配置功能>>")
                            hubeiOSDControl(result, split[2].toInt())
                        }else if (split[0] == "B" && split[1] == "S"){
                            print("湖北小视频录制功能>>")
                            hubeiVideoControl(result, split[2].toInt())
                        }else if (split[0] == "B" && split[1] == "L"){
                            print("湖北小视频录制功能>>")
                            /**
                             * cmd =1 打开
                             * cmd =0 关闭
                             */
                            hubeiLiveControl(result, split[2].toInt(), split[3].toInt())
                        }
                        else
                        {
                            split.forEach {
                                result.add(it.toInt(16).toByte())
                            }
                        }
                        val length = result.size - 24
                        result[2] = length.toByte()
                        result[3] = (length shr 8 and 0xff).toByte()
                        val crc = I2Helper.crc16(result.subList(2, result.size).toByteArray())
                        result.add(crc[0])
                        result.add(crc[1])
                        result.add(0x96.toByte())
                        channel.writeAndFlush(result.toByteArray())
                    }
                }
                channel.closeFuture().sync()
            }
            catch (e: Exception)
            {
                e.printStackTrace()
            }
            finally
            {
                group.shutdownGracefully()
            }
        }

        /**
         * 控制实时视频
         * result数组
         * control操作 0关闭 1打开
         * channel通道
         */
        fun controlLiveVideo(result: ArrayList<Byte>, control: Int, channel: Int){

                result.add(0x17.toByte())
                result.add(0xB1.toByte())
                result.add(0xff.toByte())

                result.add(channel.toByte())
                result.add(control.toByte())

                var address = "rtmp://192.168.4.103:1935/live/$channel"
                val addData = address.toByteArrayByASCII()
                val addLength = addData.size

                result.add((addLength and 0xff).toByte())
                result.add((addLength shr 8 and 0xFF).toByte())

                addData.forEach {
                    result.add(it)
                }
        }

        /**
         * 控制OSD
         */
        fun controlOSD(result: ArrayList<Byte>, channel: Int){
            val requestFlag = 1 // 0查询 1配置
            val dataFlag = 1 // 0不显示 1显示
            val textFlag = 1 //0不显示 1显示
            val textInfo = "驰昊123456"
            val textData = textInfo.toByteArray(Charsets.UTF_8)

            result.add(0x17.toByte())
            result.add(0xb3.toByte())
            result.add(0xff.toByte())

            result.add(channel.toByte())
            result.add(requestFlag.toByte())
            result.add(dataFlag.toByte())
            result.add(textFlag.toByte())
            for (index in 0 until 64){
                if (index < textData.size){
                    result.add(textData[index])
                } else {
                    result.add(0)
                }
            }

        }

        /**
         * 控制图片分辨率
         */
        fun controlPicCfg(result: ArrayList<Byte>, channel: Int){
            val requestSetFlag = 1 //0 查询 1配置
            val request = 0x02
            val colorSet = 0 //0 黑白 1彩色
            val solution= 6 //分辨率
            val lumin = 0 //亮度
            val con = 0//对比度
            val sta = 0 //饱和度

            result.add(0x07.toByte())
            result.add(0xb1.toByte())
            result.add(0xff.toByte())

            result.add(requestSetFlag.toByte())
            result.add(request.toByte())
            result.add(channel.toByte())
            result.add(colorSet.toByte())
            result.add(solution.toByte())
            result.add(lumin.toByte())
            result.add(con.toByte())
            result.add(sta.toByte())
        }

        /**
         * 手动拍图
         */
        fun controlTakePic(result: ArrayList<Byte>, channel: Int, preset: Int){
            result.add(0x07.toByte())
            result.add(0xb3.toByte())
            result.add(0xff.toByte())

            result.add(channel.toByte())
            result.add(preset.toByte())
        }

        /**
         * 心跳回复
         */
        fun heartControl(result: ArrayList<Byte>){
            result.add(0x0A.toByte())
            result.add(0xc1.toByte())
            result.add(0xff.toByte())
            result.add(0xff.toByte())
            result.add(0xff.toByte())

            result.add(0x0.toByte())
            result.add(0x0.toByte())
            result.add(0x0.toByte())
            result.add(0x0.toByte())
        }

        /**
         * 风阈值
         */
        fun windControl(result: ArrayList<Byte>,type: Int) {
            result.add(0x03.toByte())
            result.add(0xA7.toByte())
            result.add(0xff.toByte())

            result.add(type.toByte())//requestflag

            result.add(4)//size
            result.add(0x7a) //zqlzql
            result.add(0x71)
            result.add(0x6c)
            result.add(0x7a)
            result.add(0x71)
            result.add(0x6c)
            result.add(0x01)//int
            result.add(0x64)
            result.add(0x00)
            result.add(0x00)
            result.add(0x00)

            result.add(0x7a) //zqlzql
            result.add(0x71)
            result.add(0x6c)
            result.add(0x00)
            result.add(0x00)
            result.add(0x00)
            result.add(0x01)//int
            result.add(0x63)
            result.add(0x00)
            result.add(0x00)
            result.add(0x00)

            result.add(0x7a) //zqlzql
            result.add(0x71)
            result.add(0x6c)
            result.add(0x00)
            result.add(0x00)
            result.add(0x00)
            result.add(0x02)//int
            result.add(0x33)
            result.add(0x33)
            result.add(0x85.toByte())
            result.add(0x42.toByte())

            result.add(0x7a) //zqlzql
            result.add(0x71)
            result.add(0x6c)
            result.add(0x00)
            result.add(0x00)
            result.add(0x00)
            result.add(0x00)//int
            result.add(0x37)
            result.add(0x00)
            result.add(0x00)
            result.add(0x00)

        }

        /**
         * 安徽扩展OSD功能
         */
        fun anOSDControl(result: ArrayList<Byte>,channel: Int, type: Int){
            result.add(0x07.toByte())
            result.add(0xe4.toByte())
            result.add(0xff.toByte())

            result.add(channel.toByte())//channel
            result.add(type.toByte())//requestflag
            result.add(0x01)//showtime
            result.add(0x01)//showtext

            val textInfo = "驰昊123456"
            val textData = textInfo.toByteArray(Charsets.UTF_8)

            for (index in textData){
                result.add(index)
            }

        }

        /**
         * 江苏扩展拍照时间表
         */
        fun timeConfig2Conbtrol(result: ArrayList<Byte>,channel: Int, type: Int){
            result.add(0x07.toByte())
            result.add(0xb9.toByte())
            result.add(0xff.toByte())

            result.add(type.toByte())//requestflag
            result.add(channel.toByte())//channel
            result.add(0x01)//preset
            result.add(0x02)//group
            result.add(0x0c)//startHour
            result.add(0)//startMinute
            result.add(5)//endHour
            result.add(0)//endMin
            result.add(0x3C)//fre
            result.add(0x0d)//startHour
            result.add(0)//startMinute
            result.add(0x14)//endHour
            result.add(0)//endMin
            result.add(0x3C)//fre
        }

        /**
         * 江苏扩展预置位
         */
        fun presetConfig2Control(result: ArrayList<Byte>, type: Int){
            result.add(0x07.toByte())
            result.add(0xba.toByte())
            result.add(0xff.toByte())

            val preset = 6
            val textInfo = "驰昊123456"
            val textData = textInfo.toByteArray(Charsets.UTF_8)

            result.add(type.toByte()) //REQUEST
            result.add(0x01) //CHANNEL
            result.add(0x01) //GROUP
            if (type != 2){
                result.add(preset.toByte()) //PRESETNO
                result.add(textData.size.toByte())
                for (index in textData){
                    result.add(index)
                }
            } else {
                result.add(preset.toByte()) //PRESETNO
                result.add(0)
            }

        }

        /**
         * 江苏扩展升级功能
         */
        fun updateControl(result: ArrayList<Byte>, type: Int){
            result.add(0x13.toByte())
            result.add(0xa6.toByte())
            result.add(0xff.toByte())

            result.add(type.toByte())

            val HttpInfo = "https://juejin.cn/login?ActivityId=1708485931584542&RedirectUrl=live.juejin.cn%2Fapiservice%2Fstate%2F4354%2Fxdc2021%3Futm_source%3Djuejinweb&Timestamp=1637227677946"
            val HttpData = HttpInfo.toByteArray(Charsets.UTF_8)


            for (index in 0 until 260){
                if (index < HttpData.size){
                    result.add(HttpData[index])
                } else {
                    result.add(0)
                }
            }

            val pathInfo = "www.tencent.com/123456/789123"
            val pathData = pathInfo.toByteArray(Charsets.UTF_8)


            for (index in 0 until 260){
                if (index < pathData.size){
                    result.add(pathData[index])
                } else {
                    result.add(0)
                }
            }
        }


        /**
         * 江苏ai扩展
         */
        fun aiConfig2Control(result: ArrayList<Byte>, type: Int){
            result.add(0x17.toByte())
            result.add(0xbe.toByte())
            result.add(0xff.toByte())
            result.add(0x04.toByte())//channel
            result.add(type.toByte())//type
            result.add(0x01.toByte())//count
            result.add(0x0d)//startHour
            result.add(0)//startMinute
            result.add(0x14)//endHour
            result.add(0)//endMin
            result.add(0)//preset
            result.add(0x3C)//fre
            result.add(0x01)//level
            result.add(0x01)//act

        }

        /**
         * 湖北OSD
         */
        fun hubeiOSDControl(result: ArrayList<Byte>, type: Int){
            result.add(0x07.toByte())
            result.add(0xba.toByte())
            result.add(0xff.toByte())
            result.add(type.toByte())//type
            result.add(0x01.toByte())//channel

            val textInfo = "驰昊123456"
            val textData = textInfo.toByteArray(Charsets.UTF_8)
            for (index in 0 until 129){
                if (index < textData.size){
                    result.add(textData[index])
                } else {
                    result.add(0)
                }
            }
            result.add(0x02)
            for (index in 0 until 39){
                result.add(0)
            }
        }

        /**
         * 湖北SmallVideo
         */
        fun hubeiVideoControl(result: ArrayList<Byte>, channel: Int){
            result.add(0x07.toByte())
            result.add(0xbc.toByte())
            result.add(0xff.toByte())
            result.add(channel.toByte())//channel
            result.add(0)//preset
            result.add(0x01.toByte())//channel
        }

        /**
         * 湖北live
         */
        fun hubeiLiveControl(result: ArrayList<Byte>, cmd: Int, channel: Int){
            result.add(0x07.toByte())
            result.add(0xb9.toByte())
            result.add(0xff.toByte())
            result.add(cmd.toByte())

            val pathInfo = "rtmp//:192.168.1.38:1290/123456/789123"
            val pathData = pathInfo.toByteArray(Charsets.UTF_8)

            for (index in 0 until 128){
                if (index < pathData.size){
                    result.add(pathData[index])
                } else {
                    result.add(0)
                }
            }

            result.add(channel.toByte())//channel
        }
    }
}




